package com.love.rongapi.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.love.rongapi.constant.ApiEnum;
import com.love.rongapi.mapper.UserMapper;
import com.love.rongapi.model.User;
import com.love.rongapi.model.request.*;
import com.love.rongapi.model.response.UserResponse;
import com.love.rongapi.service.UserService;
import com.love.rongcommon.constant.AppKey;
import com.love.rongcommon.jwt.JwtUtil;
import com.love.rongcommon.vo.AccessTokenVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final static String CHINESE = "chinese.txt";
    private final static String REDIS_KEY_CHINESE = "chinese:content";

    @Value("${global.prefix.nickName:乱七八糟}")
    private String globalPrefixNickName;

    @Resource(name = "stringRedisTemplate_0")
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Boolean initNickName() {
        try {
            String redisValue = stringRedisTemplate.opsForValue().get(REDIS_KEY_CHINESE);
            if (ObjectUtil.isEmpty(redisValue)) {
                ClassLoader classLoader = getClass().getClassLoader();
                URL url = classLoader.getResource(CHINESE);
                File file = new File(url.getFile());
                if (file.exists()) {
                    StringBuffer buffer = new StringBuffer();
                    BufferedReader in = new BufferedReader(new FileReader(file));
                    String str;
                    while ((str = in.readLine()) != null) {
                        buffer.append(str);
                    }
                    // 添加缓存
                    stringRedisTemplate.opsForValue().set(REDIS_KEY_CHINESE, buffer.toString());
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    public String createAccessToken(AccessTokenGetRequest request) {
        User user = this.getById(request.getUserId());
        ApiEnum.USER_NOT_EXISTS.isNotEmpty(user);

        // 创建AccessToken
        AccessTokenVo accessTokenVo = request.convert(AccessTokenVo.class);
        accessTokenVo = JwtUtil.encode(accessTokenVo);

        // 保存Redis
        String key = StrFormatter.format("{}:{}", AppKey.ACCESS_TOKEN_KEY, accessTokenVo.getUserId());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(accessTokenVo), 1, TimeUnit.MINUTES);

        return accessTokenVo.getAccessToken();
    }

    @Override
    public Boolean saveUser(UserSaveRequest request) {
        Wrapper<User> wrapper = Wrappers.<User>lambdaQuery()
                .eq(ObjectUtil.isNotEmpty(request.getMobile()), User::getMobile, request.getMobile())
                .eq(User::getEnable, Boolean.TRUE);
        List<User> list = this.list(wrapper);
        ApiEnum.MOBILE_EXISTS.isEmpty(list);

        User user = new User();
        user.setMobile(request.getMobile());
        user.setNickName(Convert.toStr(request.getNickName(), globalPrefixNickName + RandomUtil.randomInt(1, 888)));
        user.setUserName(Convert.toStr(request.getUserName(), createUserName()));
        boolean save = this.save(user);
        ApiEnum.FAILED_SAVE.isTrue(save);
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateUser(UserUpdateRequest request) {
        // 校验手机号码唯一性
        if (ObjectUtil.isNotEmpty(request.getMobile())) {
            List<User> list = this.lambdaQuery().eq(User::getMobile, request.getMobile())
                    .eq(User::getEnable, true)
                    .notIn(User::getId, request.getId())
                    .list();
            ApiEnum.MOBILE_EXISTS.isEmpty(list);
        }

        User user = request.convert(User.class);
        boolean update = this.updateById(user);
        ApiEnum.FAILED_UPDATE.isTrue(update);
        return Boolean.TRUE;
    }

    @Override
    public Boolean deleteUser(UserDeleteRequest request) {
        Wrapper<User> wrapper = Wrappers.<User>lambdaUpdate()
                .set(User::getEnable, Boolean.FALSE)
                .set(User::getUpdateTime, LocalDateTime.now())
                .eq(User::getEnable, Boolean.TRUE)
                .in(User::getId, request.getIds());
        boolean update = this.update(wrapper);
        ApiEnum.FAILED_DELETE.isTrue(update);
        return Boolean.TRUE;
    }

    @Override
    public UserResponse getUser(UserGetRequest request) {
        User user = this.getById(request.getUserId());
        ApiEnum.USER_NOT_EXISTS.isNotNull(user);
        ApiEnum.USER_DISABLE.isTrue(user.getEnable());
        return BeanUtil.copyProperties(user, UserResponse.class);
    }

    private String createUserName() {
        String redisValue = stringRedisTemplate.opsForValue().get(REDIS_KEY_CHINESE);
        if (ObjectUtil.isNotEmpty(redisValue)) {
            int length = redisValue.length() - 1;
            int nickNameLength = RandomUtil.randomInt(1, 5);
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < nickNameLength; i++) {
                buffer.append(redisValue.charAt(RandomUtil.randomInt(0, length)));
            }
            return buffer.toString();
        }
        return null;
    }
}
